using System;
using System.IO;
using System.Linq;
using Crawler.ApplicationServices;
using Crawler.Domain.DataEntities;
using Crawler.Domain.DataEntities.Crawling;
using Crawler.DomainServices.Processors;
using HtmlAgilityPack;
using StructureMap;

namespace Crawler.DomainServices.Pages
{
	public class ImdbMoviePage
	{
		private readonly IHtmlParserHelper _helper;
		private readonly string _url;
		private string _coverPictureUrl;
		private int _durationMinutes;
		private DateTime _firstReleaseDate;
		private string _genres;
		private float _imdbRating;
		private int _ratingCount;
		private DateTime _utcCrawled;
		private HtmlDocument _document;
		private string _title;
		private int _year;

		private ImdbMoviePage(string url)
		{
			_url = url;
			_helper = ObjectFactory.GetInstance<IHtmlParserHelper>();
		}

		private ImdbMoviePage(RawPageCrawlInfo rawPage):this(rawPage.FromUrl)
		{
			_document = new HtmlDocument();
			string readAllText = File.ReadAllText(rawPage.FilePath);
			_document.LoadHtml(readAllText);
		}

		public string ImdbId
		{
			get { return new Uri(Url).Segments.Last().Replace(@"/", string.Empty).Trim(); }
		}

		private HtmlDocument Document
		{
			get
			{
				if (_document == null)
				{
					_document = new HtmlDocument();
					string pageHtmlText = ObjectFactory.GetInstance<IRequestsHelper>()
						.GetPageHtmlText(Url);
					_document.LoadHtml(pageHtmlText);
				}
				return _document;
			}
		}

		public string Url
		{
			get { return _url; }
		}

		public string CoverPictureUrl
		{
			get { return _coverPictureUrl; }
		}

		public int DurationMinutes
		{
			get { return _durationMinutes; }
		}

		public DateTime FirstReleaseDate
		{
			get { return _firstReleaseDate; }
		}

		public string Genres
		{
			get { return _genres; }
		}

		public float ImdbRating
		{
			get { return _imdbRating; }
		}

		public int RatingCount
		{
			get { return _ratingCount; }
		}

		public DateTime UtcCrawled
		{
			get { return _utcCrawled; }
		}

		public string Title
		{
			get { return _title; }
		}

		public int Year
		{
			get { return _year; }
		}

		public static ImdbMoviePage FromUrl(string imdbUrl)
		{
			return new ImdbMoviePage(imdbUrl);
		}

		public static ImdbMoviePage From(RawPageCrawlInfo rawPage)
		{
			return new ImdbMoviePage(rawPage);
		}

		public void Load()
		{
			HtmlNode srcOverViewTop = Document.DocumentNode.SelectSingleNode("//*[contains(@id, 'overview-top')]");
			HtmlNode srcInfoBar = Document.DocumentNode.SelectSingleNode("//*[contains(@class, 'infobar')]");

			DateTime firstReleaseDate = GetFirstReleaseDate(srcInfoBar);

			_year = firstReleaseDate.Year;
			_title = GetTitle(srcOverViewTop);
			_durationMinutes = GetDuration(srcInfoBar);

			_genres = GetGenres(srcInfoBar);
			_firstReleaseDate = firstReleaseDate;
			_imdbRating = GetRating(Document.DocumentNode.SelectSingleNode("//*[contains(@class, 'star-box-giga-star')]"));
			_ratingCount = GetRatingCount(Document.DocumentNode);
			_utcCrawled = DateTime.UtcNow;
			_coverPictureUrl =
				GetCoverPictureUrl(_helper.GetInnerNode(Document.DocumentNode, "//*[contains(@id, 'img_primary')]"));
		}

		private string GetCoverPictureUrl(HtmlNode node)
		{
			string txt = _helper.GetAttributeValueOfSingleNode(node, "//*[contains(@itemprop, 'image')]", "src");

			return txt;
		}


		private int GetRatingCount(HtmlNode src)
		{
			string txt = _helper.GetInnerTextOfSingleNode(src, "//*[contains(@itemprop, 'ratingCount')]")
				.Replace(",", string.Empty);
			return int.Parse(txt);
		}

		private DateTime GetFirstReleaseDate(HtmlNode src)
		{
			string txt;
			try
			{
				txt = _helper.GetAttributeValueOfSingleNode(src, "//*[contains(@itemprop, 'datePublished')]", "content");
			}
			catch
			{
				txt = "1800";
			}
			try
			{
				return DateTime.Parse(txt);
			}
			catch
			{
				return new DateTime(int.Parse(txt), 1, 1);
			}
		}

		private int GetDuration(HtmlNode src)
		{
			string trim =
				_helper.GetInnerTextOfSingleNode(src, "//*[contains(@itemprop, 'duration')]").Replace("min", string.Empty).Trim();

			return string.IsNullOrEmpty(trim) ? -1 : int.Parse(trim);
		}

		private string GetGenres(HtmlNode src)
		{
			return string.Join(", ",
				_helper.GetInnerNodeCollection(src, "//*[contains(@itemprop, 'genre')]").Select(x => x.InnerText));
		}

		private float GetRating(HtmlNode src)
		{
			return float.Parse(src.InnerText.Trim());
		}

		private string GetTitle(HtmlNode src)
		{
			return _helper.GetInnerTextOfSingleNode(src, "//*[contains(@itemprop, 'name')]");
		}

		
	}
}